package com.mc.linklist;

import java.util.LinkedList;

/***
 * @ClassName MyLinkedList
 * @Description todo
 * @Author CC
 * @Date: 2019/10/2813:39
 * @Version 1.0
 */
public class MyLinkedList<E> {
    private Node<E> first;
    private Node<E> last;
    private int size = 0;


    public boolean add(E e) {
        linkLast(e);
        return true;
    }

    public void add(int index, E e) {
        checkIndex(index);
        //直接给尾部添加
        if (index == size) {
            linkLast(e);
        } else {
            linkBefore(e, node(index));
        }
    }

    public E remove(int index) {
        checkIndex(index);
        return unLink(node(index));
    }


    public E get(int index) {
        checkIndex(index);
        final Node<E> node = node(index);
        return node.item;

    }

    public void addFirst(E e) {
        linkFirst(e);
    }

    public void addLast(E e) {
        linkLast(e);
    }


    public int size() {
        return size;
    }

    public E getFirst() {
        if (first == null)
            try {
                throw new Exception("no suchElement！");
            } catch (Exception e) {
                e.printStackTrace();
            }
        return first.item;
    }


    public E getLast() {
        if (last == null) {
            try {
                throw new Exception("no suchElement！");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return last.item;
    }


    //链表删除中间某个元素
    private E unLink(Node<E> delNode) {
        final E item = delNode.item;
        final Node<E> prev = delNode.prev;
        final Node<E> next = delNode.next;
        if (prev == null) {//证明是首元素
            first = next;
        } else {
            prev.next = next;
            delNode.prev = null;
        }
        if (next == null) {
            last = prev;
        } else {
            next.prev = prev;
            delNode.next = null;
        }
        size--;
        return item;

    }


    private void linkFirst(E e) {
        final Node<E> f = first;
        final Node<E> firstNode = new Node<E>(null, e, first);
        first = firstNode;
        if (f == null) {
            //证明该集合为空
            last = firstNode;
        } else {
            f.prev = firstNode;
        }
        size++;
    }

    private void linkLast(E e) {
        //拿出下一个节点存起来
        final Node<E> l = last;
        final Node<E> newNode = new Node(l, e, null);
        //最后一个节点设置为当前新增的节点
        last = newNode;
        //如果L等于null,证明没有最有一个节点,证明该链表为null
        if (l == null) {
            first = newNode;
        } else {
            //如果不等于null那么要把当前node塞入到他下一个节点中，就是last中的nexNode中
            l.next = newNode;
        }
        size++;
    }

    private void linkBefore(E e, Node<E> oldNode) {
        final Node<E> prev = oldNode.prev;
        //拆链
        final Node<E> newNode = new Node<>(prev, e, oldNode);
        oldNode.prev = newNode;
        if (prev == null) {
            first = newNode;
        } else {
            prev.next = newNode;
        }
        size++;
    }

    /**
     * 取出对应位置的元素节点
     *
     * @param index
     * @return
     */
    Node<E> node(int index) {
        if (index < size << 1) {
            //证明index在前半部分
            //取出第一个NODE节点,循环调用
            Node<E> x = first;
            for (int i = 0; i < index; i++) {
                x = x.next;
            }
            return x;
        } else {
            //证明index 在链表的后半部分
            Node<E> x = last;
            for (int i = size - 1; i > index; i++) {
                x = x.prev;
            }
            return x;
        }
    }

    private void checkIndex(int index) {
        if (!isElementIndex(index)) {
            try {
                throw new Exception("index is illegal");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private boolean isElementIndex(int index) {
        return index >= 0 && index <= size;
    }


    //声明内部类
    private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }
}
